package wscmd

import (
	"context"
	"encoding/json"
	"github.com/shopspring/decimal"
	"go.uber.org/zap"
	"google.golang.org/protobuf/proto"
	"strconv"
	"strings"
	"time"
	"wzgames/internal/admin/adcomm"
	"wzgames/internal/admin/adsv/stmsv"
	"wzgames/internal/admin/api/wzabind"
	"wzgames/internal/client"
	"wzgames/internal/codec/sfs"
	"wzgames/internal/constant"
	"wzgames/internal/gloader"
	"wzgames/internal/model/gamep"
	"wzgames/internal/model/mcomm"
	"wzgames/internal/model/roulettep"
	"wzgames/internal/model/statement"
	"wzgames/internal/model/user"
	"wzgames/internal/response"
	"wzgames/internal/secure/routil"
	"wzgames/pkg/logger"
	"wzgames/pkg/utils/byteutil"
	"wzgames/pkg/utils/calcutil"
	"wzgames/pkg/utils/dateutil"
	"wzgames/pkg/utils/stringutil"
)

var rouHelp = &routil.RouUtil{}

var getBetPendingUnCheckCount = func(admin adcomm.IAdmin, ipt interface{}) {
	m := ipt.(*sfs.TSfsObject)
	data := m.GetContent()
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.KeyBetPendingUssCount, "bad params")
		return
	}
	data = data.GetSFSObject(sfs.ParamId)
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.KeyBetPendingUssCount, "bad params")
		return
	}
	tp, _ := stringutil.ToInt32(data.GetUtfString("tp"), 0)
	count, code := stmsv.SV().GetBetPendingUnCheckCount(wzabind.BetPendingSsReq{
		Tp: tp,
	})
	msg := response.AcquireMsgO13()
	xw := sfs.XWriter{}
	defer xw.Reset()
	xw.WriteUShort(uint16(2))
	xw.WriteStringS(sfs.CmdKey, adcomm.KeyBetPendingUssCount)
	xw.WriteSfsObjectPre(sfs.ParamId, uint16(3))
	xw.WriteShortS(sfs.KeyCode, code)
	xw.WriteLongS("count", int64(count))
	xw.WriteIntS("tp", tp)

	xw.WriteTo(msg)
	admin.SendMessage(msg)
}

var betPendingSettle1 = func(admin adcomm.IAdmin, ipt interface{}) {
	m := ipt.(*sfs.TSfsObject)
	data := m.GetContent()
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.KeyBetPendingUssSettle1, "bad params")
		return
	}
	data = data.GetSFSObject(sfs.ParamId)
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.KeyBetPendingUssSettle1, "bad params")
		return
	}
	lastBetId, _ := stringutil.ToUint64(data.GetUtfString("lastBetId"), 0)
	limit, _ := stringutil.ToInt64(data.GetUtfString("limit"), 20)
	start, _ := stringutil.ToInt64(data.GetUtfString("start"), 0)
	if start <= 0 {
		start = dateutil.UnixMilli() - 120000
	}

	req := &statement.NodeStartStmSettle{
		Start:     start,
		LastBetId: lastBetId,
		LimitNum:  limit,
		Dateline:  dateutil.UnixMilli(),
	}
	reply := &statement.NodeStartStmSettleReply{}
	rpcCtx, cancelFn := context.WithTimeout(context.Background(), time.Second*15)
	err := client.GetUCClient().Call(rpcCtx, "NodeStartSettledStmDeal", req, reply)
	cancelFn()
	code := int16(0)
	if err != nil {
		logger.Error("[WsCmd] bet pending settle stm fail", zap.Error(err))
		code = response.ErrInternal
	} else {
		code = int16(reply.Code)
	}

	msg := response.AcquireMsgO13()
	xw := sfs.XWriter{}
	defer xw.Reset()
	xw.WriteUShort(uint16(2))
	xw.WriteStringS(sfs.CmdKey, adcomm.KeyBetPendingUssSettle1)
	xw.WriteSfsObjectPre(sfs.ParamId, uint16(5))
	xw.WriteShortS(sfs.KeyCode, code)
	xw.WriteLongS("count", reply.DealCount)
	xw.WriteLongS("lastBetId", int64(reply.LastBetId))
	xw.WriteLongS("start", start)
	xw.WriteIntS("tp", 1)

	xw.WriteTo(msg)
	admin.SendMessage(msg)
}

var betPendingSettle2 = func(admin adcomm.IAdmin, ipt interface{}) {
	m := ipt.(*sfs.TSfsObject)
	data := m.GetContent()
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.KeyBetPendingUssSettle2, "bad params")
		return
	}
	data = data.GetSFSObject(sfs.ParamId)
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.KeyBetPendingUssSettle2, "bad params")
		return
	}
	betId, _ := stringutil.ToUint64(data.GetUtfString("betId"), 0)
	gact, _ := stringutil.ToInt32(data.GetUtfString("gact"), 0)
	rd, code := stmsv.SV().GetBetPending(betId)
	if code != 0 {
		admin.ErrMsg(code, adcomm.KeyBetPendingUssSettle2, "")
		return
	}
	if gact == 2 {
		code = betPendingCancel(rd)
	} else {
		payoutEnt, stepEnt, code1 := stmsv.SV().GetBetPendingStepInfo(betId)
		if code1 != 0 {
			admin.ErrMsg(code1, adcomm.KeyBetPendingUssSettle2, "")
			return
		}
		if payoutEnt == nil && stepEnt == nil {
			admin.ErrMsg(response.ErrInternal, adcomm.KeyBetPendingUssSettle2, "step data not found")
			return
		}
		code = betPendingPayout(rd, payoutEnt, stepEnt)
	}

	msg := response.AcquireMsgO13()
	xw := sfs.XWriter{}
	defer xw.Reset()
	xw.WriteUShort(uint16(2))
	xw.WriteStringS(sfs.CmdKey, adcomm.KeyBetPendingUssSettle2)
	xw.WriteSfsObjectPre(sfs.ParamId, uint16(2))
	xw.WriteShortS(sfs.KeyCode, code)
	xw.WriteLongS("betId", int64(betId))

	xw.WriteTo(msg)
	admin.SendMessage(msg)
}

var betPendingSettle3 = func(admin adcomm.IAdmin, ipt interface{}) {
	m := ipt.(*sfs.TSfsObject)
	data := m.GetContent()
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.KeyBetPendingUssSettle3, "bad params")
		return
	}
	data = data.GetSFSObject(sfs.ParamId)
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.KeyBetPendingUssSettle3, "bad params")
		return
	}
	idArr := data.GetLongArray("betIdList")
	if idArr == nil || len(idArr) == 0 {
		admin.ErrMsg(response.ErrBadRequest, adcomm.KeyBetPendingUssSettle3, "bad params")
		return
	}
	var idsArr []string
	for _, betId := range idArr {
		idsArr = append(idsArr, strconv.FormatInt(betId, 10))
	}
	ret, count, code := stmsv.SV().GetBetPendingIn(strings.Join(idsArr, ","))
	if code != 0 {
		admin.ErrMsg(code, adcomm.KeyBetPendingUssSettle3, "")
		return
	}
	var rArr []int64
	if count > 0 {
		for _, bet := range ret {
			if bet.GAct != 1 && bet.GAct != 5 {
				continue
			}
			code = betPendingCancel(bet)
			if code == 0 {
				rArr = append(rArr, int64(bet.BetId))
			}
		}
	}
	msg := response.AcquireMsgO13()
	xw := sfs.XWriter{}
	defer xw.Reset()
	xw.WriteUShort(uint16(2))
	xw.WriteStringS(sfs.CmdKey, adcomm.KeyBetPendingUssSettle3)
	xw.WriteSfsObjectPre(sfs.ParamId, uint16(2))
	xw.WriteShortS(sfs.KeyCode, 0)
	xw.WriteLongArrayS("done", rArr)

	xw.WriteTo(msg)
	admin.SendMessage(msg)
}

var betPendingSettle4 = func(admin adcomm.IAdmin, ipt interface{}) {
	m := ipt.(*sfs.TSfsObject)
	data := m.GetContent()
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.KeyBetPendingUssSettle4, "bad params")
		return
	}
	data = data.GetSFSObject(sfs.ParamId)
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.KeyBetPendingUssSettle4, "bad params")
		return
	}
	limit, _ := stringutil.ToInt64(data.GetUtfString("limit"), 20)
	instId, _ := stringutil.ToInt64(data.GetUtfString("instId"), 0)
	roundId, _ := stringutil.ToInt64(data.GetUtfString("roundId"), 0)
	nodeId, _ := stringutil.ToInt64(data.GetUtfString("nodeId"), 0)
	gact, _ := stringutil.ToInt32(data.GetUtfString("gact"), 0)
	if gact != 2 && gact != 4 {
		admin.ErrMsg(response.ErrBadRequest, adcomm.KeyBetPendingUssSettle4, "bad params - gact")
		return
	}
	rd, code := stmsv.SV().GetAviatorRound(roundId, instId)
	if code != 0 {
		admin.ErrMsg(code, adcomm.KeyBetPendingUssSettle4, "bad params")
		return
	}
	if rd.Status < 3 {
		admin.ErrMsg(response.ErrForbidden, adcomm.KeyBetPendingUssSettle4, "暂时还不能处理！")
		return
	}
	req := wzabind.BetPendingSsReq{
		PageSize: int(limit),
		NodeId:   nodeId,
		InstId:   instId,
		RoundId:  roundId,
		Tp:       4,
	}
	ret, c1 := stmsv.SV().GetBetPendingUnCheckList(admin.AdminId(), req)
	if c1 != 0 {
		admin.ErrMsg(c1, adcomm.KeyBetPendingUssSettle4, "获取待处理列表出错！")
		return
	}
	l := len(ret)
	if l > 0 {
		if gact == 4 {
			code = AvtBetPendingLoseSettle(nodeId, ret, rd.Result)
			if code != 0 {
				l = 0
			}
		} else if gact == 2 {
			c := 0
			for _, v := range ret {
				c1 = betPendingCancel(v)
				if c1 == 0 {
					c++
				}
			}
			l = c
		}
	}

	msg := response.AcquireMsgO13()
	xw := sfs.XWriter{}
	defer xw.Reset()
	xw.WriteUShort(uint16(2))
	xw.WriteStringS(sfs.CmdKey, adcomm.KeyBetPendingUssSettle4)
	xw.WriteSfsObjectPre(sfs.ParamId, uint16(6))
	xw.WriteShortS(sfs.KeyCode, code)
	xw.WriteLongS("count", int64(l))
	xw.WriteLongS("limit", limit)
	xw.WriteLongS("instId", instId)
	xw.WriteLongS("nodeId", nodeId)
	xw.WriteLongS("roundId", roundId)

	xw.WriteTo(msg)
	admin.SendMessage(msg)
}

var rouDrawLottery = func(admin adcomm.IAdmin, ipt interface{}) {
	m := ipt.(*sfs.TSfsObject)
	data := m.GetContent()
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.KeyRouBigDrawLottery, "bad params")
		return
	}
	data = data.GetSFSObject(sfs.ParamId)
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.KeyRouBigDrawLottery, "bad params")
		return
	}
	instId, _ := stringutil.ToInt64(data.GetUtfString("instId"), 0)
	roundId, _ := stringutil.ToInt64(data.GetUtfString("roundId"), 0)
	rd, code := stmsv.SV().GetRouRound(roundId, instId)
	if code != 0 {
		admin.ErrMsg(code, adcomm.KeyRouBigDrawLottery, "bad params")
		return
	}
	nt := dateutil.UnixSecs()
	if rd.Start+30 >= nt {
		admin.ErrMsg(response.ErrForbidden, adcomm.KeyRouBigDrawLottery, "未到开奖时间！")
		return
	}
	if rd.Status >= 3 {
		admin.ErrMsg(response.ErrForbidden, adcomm.KeyRouBigDrawLottery, "已开奖了！")
		return
	}
	gameCfg, c0 := GetRouletteGameConfig(instId)
	if c0 != 0 {
		admin.ErrMsg(c0, adcomm.KeyRouBigDrawLottery, "获取游戏配置出错！")
		return
	}
	ret, c1 := stmsv.SV().GetBetPendingUnCheckList(admin.AdminId(), wzabind.BetPendingSsReq{InstId: instId, RoundId: roundId, PageSize: 3})
	if c1 != 0 {
		admin.ErrMsg(c1, adcomm.KeyRouBigDrawLottery, "获取前3个投注出错！")
		return
	}
	var ids []string
	for _, ut := range ret {
		ids = append(ids, strconv.FormatUint(ut.BetId, 10))
	}
	bets, l, c2 := stmsv.SV().GetBetsInToArr(strings.Join(ids, ","))
	if c2 != 0 || l != len(ret) {
		admin.ErrMsg(c2, adcomm.KeyRouBigDrawLottery, "获取投注列表出错！")
		return
	}
	first3 := &roulettep.First3Bets{}
	ok := true
	var combineStr strings.Builder
	for _, bet := range bets {
		rouBetInfo := &statement.RouletteBigBetInfo{}
		err := json.Unmarshal(byteutil.StringToSliceByte(bet.Detail), rouBetInfo)
		if err != nil {
			logger.Error("[WsCmd] do roulette big draw fail on bet json.Unmarshal", zap.Int64("InstId", instId), zap.Int64("RoundId", roundId), zap.Error(err))
			ok = false
			break
		}
		first3.First3 = append(first3.First3, &gamep.BetUser{
			AgtId:    bet.AgtId,
			AgtKey:   "",
			Uid:      bet.Uid,
			Uname:    bet.Uname,
			Seed:     rouBetInfo.ClientSeed,
			Uhead:    "",
			Currency: bet.Curr,
		})
		combineStr.WriteString(rouBetInfo.ClientSeed)
	}
	if !ok {
		admin.ErrMsg(response.ErrInternal, adcomm.KeyRouBigDrawLottery, "gen first3 fail！")
		return
	}
	b, err1 := json.Marshal(first3)
	if err1 != nil {
		logger.Error("[WsCmd] do roulette big draw fail on json.Marshal first3 bets fail", zap.Int64("InstId", instId), zap.Int64("RoundId", roundId), zap.Error(err1))
		admin.ErrMsg(response.ErrInternal, adcomm.KeyRouBigDrawLottery, "marshal first3 fail！")
		return
	}
	rd.Clientseeds = b
	rd.End = dateutil.UnixSecs()
	rd.Updated = rd.End
	rd.Status = constant.RouManualState
	rd.Op = 1
	h512, retNum, retColor, retGrp := rouHelp.Draw(rd.Sseed, combineStr.String(), gameCfg.GameConfig)
	rd.H512 = h512
	rd.RetNum = retNum
	rd.RetColor = retColor
	rd.RetGrp = retGrp
	code = stmsv.SV().RouRoundDraw(rd)

	msg := response.AcquireMsgO13()
	xw := sfs.XWriter{}
	defer xw.Reset()
	xw.WriteUShort(uint16(2))
	xw.WriteStringS(sfs.CmdKey, adcomm.KeyRouBigDrawLottery)
	xw.WriteSfsObjectPre(sfs.ParamId, uint16(4))
	xw.WriteShortS(sfs.KeyCode, code)
	xw.WriteLongS("instId", instId)
	xw.WriteLongS("roundId", roundId)
	xw.WriteStringS("result", retNum+","+retColor+","+retGrp)

	xw.WriteTo(msg)
	admin.SendMessage(msg)
}

var rouBetPendingSettle = func(admin adcomm.IAdmin, ipt interface{}) {
	m := ipt.(*sfs.TSfsObject)
	data := m.GetContent()
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.KeyRouBetPendingUssSettle, "bad params")
		return
	}
	data = data.GetSFSObject(sfs.ParamId)
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.KeyRouBetPendingUssSettle, "bad params")
		return
	}
	limit, _ := stringutil.ToInt64(data.GetUtfString("limit"), 20)
	instId, _ := stringutil.ToInt64(data.GetUtfString("instId"), 0)
	roundId, _ := stringutil.ToInt64(data.GetUtfString("roundId"), 0)
	nodeId, _ := stringutil.ToInt64(data.GetUtfString("nodeId"), 0)
	gameCfg, c0 := GetRouletteGameConfig(instId)
	if c0 != 0 {
		admin.ErrMsg(c0, adcomm.KeyRouBetPendingUssSettle, "获取游戏配置出错！")
		return
	}
	rd, code := stmsv.SV().GetRouRound(roundId, instId)
	if code != 0 {
		admin.ErrMsg(code, adcomm.KeyRouBetPendingUssSettle, "bad params")
		return
	}
	if rd.Status < 3 {
		admin.ErrMsg(response.ErrForbidden, adcomm.KeyRouBetPendingUssSettle, "未开奖！")
		return
	}
	req := wzabind.BetPendingSsReq{
		PageSize: int(limit),
		NodeId:   nodeId,
		InstId:   instId,
		RoundId:  roundId,
		Tp:       5,
	}
	ret, c1 := stmsv.SV().GetBetPendingUnCheckList(admin.AdminId(), req)
	if c1 != 0 {
		admin.ErrMsg(c1, adcomm.KeyRouBetPendingUssSettle, "获取待处理列表出错！")
		return
	}
	var ids []string
	for _, ut := range ret {
		ids = append(ids, strconv.FormatUint(ut.BetId, 10))
	}
	bets, _, c2 := stmsv.SV().GetBetsInToArr(strings.Join(ids, ","))
	if c2 != 0 {
		admin.ErrMsg(c2, adcomm.KeyRouBetPendingUssSettle, "获取投注列表出错！")
		return
	}
	var dones int64
	gameCurrs := map[int64]*gamep.GameCurrency{}
	for _, bet := range bets {
		rouBetInfo := &statement.RouletteBigBetInfo{}
		err := json.Unmarshal(byteutil.StringToSliceByte(bet.Detail), rouBetInfo)
		if err != nil {
			logger.Error("[WsCmd] do roulette big bet settle fail on json.Unmarshal", zap.Uint64("BetId", bet.BetId), zap.Error(err))
			continue
		}
		if rouBetPendingPayout(bet, rouBetInfo, gameCfg.GameConfig, rd, gameCurrs) == 0 {
			dones++
		}
	}

	msg := response.AcquireMsgO13()
	xw := sfs.XWriter{}
	defer xw.Reset()
	xw.WriteUShort(uint16(2))
	xw.WriteStringS(sfs.CmdKey, adcomm.KeyRouBetPendingUssSettle)
	xw.WriteSfsObjectPre(sfs.ParamId, uint16(6))
	xw.WriteShortS(sfs.KeyCode, code)
	xw.WriteLongS("count", dones)
	xw.WriteLongS("limit", limit)
	xw.WriteLongS("instId", instId)
	xw.WriteLongS("nodeId", nodeId)
	xw.WriteLongS("roundId", roundId)

	xw.WriteTo(msg)
	admin.SendMessage(msg)
}

func AvtBetPendingLoseSettle(nodeId int64, data []*user.WalletBetPending, maxMultiplier float64) int16 {
	req := &statement.SettleStmList{
		NodeId:   nodeId,
		GType:    1,
		Dateline: dateutil.UnixMilli(),
		Op:       1,
		States:   []*statement.StmState{},
	}
	for _, v := range data {
		req.States = append(req.States, &statement.StmState{
			BetId:      v.BetId,
			GAct:       mcomm.GameAction_GameLoseSettle,
			GameId:     v.GameId,
			RoundId:    v.RoundId,
			Multiplier: maxMultiplier,
		})
	}
	reply := &mcomm.CodeRet{}
	rpcCtx, cancelFn := context.WithTimeout(context.Background(), time.Second*15)
	err := client.GetUCClient().Call(rpcCtx, "UpBetPendingSettle", req, reply)
	cancelFn()
	if err != nil {
		logger.Error("[WsCmd] update avt bet pending lose settle fail", zap.Int64("NodeId", req.NodeId), zap.Error(err))
		return response.ErrInternal
	}
	return int16(reply.Code)
}

func betPendingCancel(bet *user.WalletBetPending) int16 {
	req := &statement.PlayCancel{
		BetId:    bet.BetId,
		Op:       1,
		Dateline: dateutil.UnixMilli(),
		GameId:   bet.GameId,
	}
	reply := &user.BalanceRet{}
	rpcCtx, cancelFn := context.WithTimeout(context.Background(), time.Second*10)
	err := client.GetUCClient().Call(rpcCtx, "BetCancel", req, reply)
	cancelFn()
	if err != nil {
		logger.Error("[WsCmd] update bet pending cancel settle fail", zap.Uint64("BetId", bet.BetId), zap.Error(err))
		return response.ErrInternal
	}

	return int16(reply.Code)
}

func betPendingPayout(bet *user.WalletBetPending, payoutEnt *statement.PlayPayoutEnt, stepEnt *statement.PlayStepEnt) int16 {
	req := &statement.PlayPayout{
		BetId:    bet.BetId,
		RoundId:  bet.RoundId,
		GameAct:  mcomm.GameAction_GameCashOut,
		Dateline: dateutil.UnixMilli(),
		Op:       1,
		GameId:   bet.GameId,
	}
	if payoutEnt != nil {
		req.RoundId = payoutEnt.RoundId
		req.Win = payoutEnt.Win
		req.WinAmt = payoutEnt.WinAmt
		req.Payout = payoutEnt.Payout
		req.Detail = payoutEnt.Detail
	} else {
		req.RoundId = stepEnt.RoundId
		req.Win = stepEnt.Win
		req.WinAmt = stepEnt.WinAmt
		req.Payout = stepEnt.Payout
		req.Detail = stepEnt.Detail
	}
	if req.Win == mcomm.GameResult_GameLose {
		req.GameAct = mcomm.GameAction_GameLoseSettle
	}
	reply := &user.BalanceRet{}
	rpcCtx, cancelFn := context.WithTimeout(context.Background(), time.Second*10)
	err := client.GetUCClient().Call(rpcCtx, "Payout", req, reply)
	cancelFn()
	if err != nil {
		logger.Error("[WsCmd] update bet pending payout settle fail", zap.Uint64("BetId", bet.BetId), zap.Error(err))
		return response.ErrInternal
	}

	return int16(reply.Code)
}

func GetRouletteGameConfig(instId int64) (*roulettep.RouletteConfig, int16) {
	instData := gloader.GameMgr().LoadRouletteInstById(instId)
	if instData == nil {
		return nil, response.ErrInternal
	}
	gameInst := &gamep.GameInst{}
	err := proto.Unmarshal(instData, gameInst)
	if err != nil {
		logger.Error("[WsCmd] get roulette game inst config fail", zap.Int64("InstId", instId), zap.Error(err))
		return nil, response.ErrInternal
	}
	instCfg := &roulettep.RouletteConfig{}
	err = proto.Unmarshal(gameInst.Conf, instCfg)
	if err != nil {
		logger.Error("[WsCmd] get roulette game inst game config fail", zap.Int64("InstId", instId), zap.Error(err))
		return nil, response.ErrInternal
	}

	return instCfg, 0
}

func rouBetPendingPayout(bet *statement.PlayBetEnt, rouBet *statement.RouletteBigBetInfo, gameCfg *roulettep.RouletteGameConfig, rd *roulettep.RouletteRoundEntity, gCurrs map[int64]*gamep.GameCurrency) int16 {
	gameCurr, ok := gCurrs[bet.GcId]
	if !ok {
		gameCurr, _ = client.GetGameCurrency(bet.GcId)
		if gameCurr == nil {
			return response.ErrInternal
		}
		gCurrs[bet.GcId] = gameCurr
	}
	req := &statement.PlayPayout{
		BetId:    bet.BetId,
		RoundId:  bet.RoundId,
		Dateline: dateutil.UnixMilli(),
		Op:       1,
		GameId:   bet.GameId,
	}
	betTotal, totalPay := rouHelp.CalcMultiplier(gameCfg, rouBet.ChipArr, rd.RetNum, rd.RetColor, rd.RetGrp)
	if totalPay.IsZero() {
		req.GameAct = mcomm.GameAction_GameLoseSettle
	} else {
		req.GameAct = mcomm.GameAction_GameCashOut
	}
	multiplier := totalPay.Div(betTotal)
	winAmt := totalPay.Truncate(bet.Precision).String()
	winAmt, _ = CheckMaxWin(winAmt, gameCurr)
	rouBet.Multiplier = calcutil.RoundFloorD(multiplier)
	rouBet.RetNum = rd.RetNum
	rouBet.RetColor = rd.RetColor
	rouBet.RetGrp = rd.RetGrp
	req.Win = calcutil.CheckGameResult(multiplier)
	req.WinAmt = winAmt
	req.Payout = multiplier.String()
	b, err := json.Marshal(rouBet)
	if err != nil {
		logger.Error("[WsCmd] update roulette bet pending payout settle fail on json.Marshal roulette bet", zap.Uint64("BetId", bet.BetId), zap.Error(err))
		return response.ErrInternal
	}
	req.Detail = byteutil.SliceByteToString(b)

	reply := &user.BalanceRet{}
	rpcCtx, cancelFn := context.WithTimeout(context.Background(), time.Second*10)
	err = client.GetUCClient().Call(rpcCtx, "Payout", req, reply)
	cancelFn()
	if err != nil {
		logger.Error("[WsCmd] update roulette bet pending payout settle fail", zap.Uint64("BetId", bet.BetId), zap.Error(err))
		return response.ErrInternal
	}

	return int16(reply.Code)
}

func CheckMaxWin(winAmt string, gameCurr *gamep.GameCurrency) (string, float64) {
	var maxWinD decimal.Decimal
	amt, _ := decimal.NewFromString(winAmt)
	if gameCurr.VType == mcomm.ValueType_Float64Type {
		maxWinD = decimal.NewFromFloat(gameCurr.FloatValueLimit.MaxUserWin)
	} else {
		maxWinD, _ = decimal.NewFromString(gameCurr.StrValueLimit.MaxUserWin)
	}
	if maxWinD.IsPositive() && amt.GreaterThan(maxWinD) {
		maxF, _ := maxWinD.Float64()
		return maxWinD.String(), maxF
	}
	wFloat, _ := amt.Float64()
	return winAmt, wFloat
}
